package callback.impl;

import app.FileMeta;
import callback.ScanCallBack;
import util.DBUtil;
import util.PinyinUtil;

import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

/**
 * 文件扫描信息保存到数据库的回调类
 * @author yuisama
 * @date 2022/06/12 11:06
 **/
public class FileSave2DB implements ScanCallBack {
    /**
     * 将当前路径下的所有文件和文件夹信息保存到数据库中
     * @param dir
     */
    @Override
    public void callback(File dir) {
        File[] files = dir.listFiles();
        List<FileMeta> loclas = new ArrayList<>();
        if (files != null && files.length != 0) {
            for (File file : files) {
                // 扫描当前路径下文件，保存到缓存中
                loclas.add(new FileMeta(file));
            }
        }
        // 从db中查询当前路径下的文件信息
        List<FileMeta> dbFiles = query(dir);
        // 本地有，数据库没有，做插入
        for (FileMeta meta : loclas) {
            if (!dbFiles.contains(meta)) {
                save(meta);
            }
        }
        // 数据库有，本地没有，做删除
        // 如果是文件夹，还需要将文件夹和子文件夹的所有内容都删除
        for (FileMeta meta : dbFiles)  {
            if (!loclas.contains(meta)) {
                delete(meta);
            }
        }
    }
    // 将指定的文件列表写入数据库
    @Override
    public void save2DB(List<FileMeta> fileMetas) {
        Iterator<FileMeta> iterator = fileMetas.iterator();
        while (iterator.hasNext()) {
            FileMeta meta = iterator.next();
            if (Objects.nonNull(meta)) {
                save(meta);
            }
        }
    }

    /**
     * 删除数据库中当前文件信息
     * 若当前传入的是路径，还需要删除当前路径以及子路径下对应的所有文件
     * @param meta
     */
    private void delete(FileMeta meta) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "delete from file_meta where" +
                    " (name = ? and path = ? and is_directory = ?)"; // 删除文件本身
            // meta是文件夹，还需要删除当前文件夹和子文件夹下的所有信息
            if (meta.getDirectory()) {
                sql += " or path = ?"; // 删除当前路径下的所有文件信息
                sql += " or path like ?"; // 删除子文件和子文件夹
            }
            statement = connection.prepareStatement(sql);
            statement.setString(1, meta.getName());
            statement.setString(2, meta.getPath());
            statement.setBoolean(3, meta.getDirectory());
            if (meta.getDirectory()) {
                // 当前路径
                statement.setString(4, meta.getPath() + File.separator + meta.getName());
                // 子路径
                statement.setString(5, meta.getPath() + File.separator + meta.getName()
                + File.separator + "%");
            }
//            System.out.println("执行文件删除操作,sql为" + statement);
            int rows = statement.executeUpdate();
//            if (meta.getDirectory()) {
//                System.out.println("文件夹删除成功,共删除" + rows + "条记录");
//            }else {
//                System.out.println("文件删除成功");
//            }
        }catch (SQLException e) {
            throw new RuntimeException("删除文件操作出错，请检查sql语句" + e);
        }finally {
            DBUtil.close(statement);
        }
    }

    /**
     * 从数据库中查询当前路径下的所有文件信息
     * @param dir
     * @return
     */
    private List<FileMeta> query(File dir) {
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<FileMeta> result = new ArrayList<>();
        try {
            connection = DBUtil.getConnection();
            String sql = "select name, path, is_directory, size, last_modified" +
                    " from file_meta where path = ?";
            ps = connection.prepareStatement(sql);
            ps.setString(1,dir.getPath());
            rs = ps.executeQuery();
            while (rs.next()) {
                String name = rs.getString("name");
                String path = rs.getString("path");
                Boolean isDir = rs.getBoolean("is_directory");
                Long size = rs.getLong("size");
                java.util.Date date = rs.getDate("last_modified");
                result.add(new FileMeta(name,path,isDir,size,date));
            }
            return result;
        }catch (SQLException e) {
            throw new RuntimeException("查询文件信息失败" + e);
        }finally {
            DBUtil.close(rs,ps);
        }
    }

    /**
     * 将当前文件信息保存到数据库中
     * @param meta 文件信息
     */
    private void save(FileMeta meta) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DBUtil.getConnection();
            String sql = "insert into file_meta values(?,?,?,?,?,?,?)";
            statement = connection.prepareStatement(sql);
            // 文件名
            statement.setString(1,meta.getName());
            // 文件路径，此处要保存当前文件的父路径
            statement.setString(2,meta.getPath());
            // 是否为文件夹
            statement.setBoolean(3,meta.getDirectory());
            // 文件大小，单位Byte
            statement.setLong(4,meta.getSize());
            // 上次修改时间，TimeStamp类型
            statement.setTimestamp(5,new Timestamp(meta.getLastModified().getTime()));
            // 文件名包含中文才保存全拼和首字母
            String pinYinAll = null;
            String pinYinFir = null;
            if (PinyinUtil.strContainsChinese(meta.getName())) {
                String[] ret = PinyinUtil.getPinYinByFileName(meta.getName());
                pinYinAll = ret[0];
                pinYinFir = ret[1];
            }
            statement.setString(6,pinYinAll);
            statement.setString(7,pinYinFir);
//            System.out.println("执行文件信息保存操作，SQL为 : " + statement);
            int rows = statement.executeUpdate();
//            System.out.println("成功保存" + rows + "行文件信息");
        }catch (SQLException e) {
            throw new RuntimeException("文件保存失败，大家检查下Insert SQL语句 : " + e);
        }finally {
            DBUtil.close(statement);
        }
    }

    public static void main(String[] args) {
        long max = Runtime.getRuntime().maxMemory();
        String[] ret = {"b","kb","mb","GB","TB"};
        int index = 0;
        while (max > 1024) {
            max /= 1024;
            index ++;
        }
        System.out.println(max + ret[index]);
//        File file = new File("/Users/liuyiming/Desktop/测试删除");
//        FileMeta meta = new FileMeta(file);
//        System.out.println(meta);
//        // 当前路径 = path + File.Separator + name
//        System.out.println(meta.getPath() + File.separator + meta.getName());
//        // 当前路径下的子文件路径 = path + File.Separator + name + File.Separator + %
//        System.out.println(meta.getPath() + File.separator + meta.getName() + File.separator);
    }

}
